use std::collections::HashMap;
use crate::dynf::ast::BoolOperator;
#[derive(Clone, PartialEq,Debug)]
pub struct CodeObject {
    pub name:String,
    pub instructions: Vec<Instruction>,
    pub arg_names:Vec<String>,
    pub label_map: HashMap<Label, usize>
}

impl CodeObject {
    pub fn new(name:&str) -> Self {
        CodeObject {
            name:name.to_owned(),
            instructions: vec![],
            arg_names:vec![],
            label_map:Default::default()
        }
    }

    pub fn emit(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }

    pub fn set_label(&mut self,label:Label) {
        let position = self.instructions.len();
        self.label_map.insert(label, position);
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Instruction {
    LoadName(String),
    StoreName(String),
    LoadConst(Constant),
    BinaryOperation (BinaryOperator),
    Pop,
    ReturnValue,
    MakeFunction,
    JumpIfFalse(Label),
    JumpIfTrue(Label),
    UnaryOperation(UnaryOperator),
    Boolperation(BoolOperator),
    Jump(Label),
    SetupLoop {
        start: Label,
        end: Label,
    },
    PopBlock,
    CallFunction(usize),
    Break,
    Continue,
    BuildList(usize),
    StoreList,
    ListIndex
}

#[derive(Debug, Clone, PartialEq)]
pub enum Constant {
    Integer { value: i64 },
    Float { value: f64 },
    Boolean { value: bool },
    String { value: String },
    Bytes { value: Vec<u8> },
    Code { code: CodeObject },
    None
}

#[derive(Debug, Clone, PartialEq)]
pub enum BinaryOperator {
    Power,
    Multiply,
    Divide,
    FloorDivide,
    Modulo,
    Add,
    Subtract,
    Lshift,
    Rshift,
    And,
    Xor,
    Or,
}

#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOperator {
    Not
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Label(usize);

impl Label {
    pub fn new(label: usize) -> Self {
        Label(label)
    }
}